/*
 * SRU class handles the Shift and Rotate operations.  SRU is an acronym for 
 * Shift and Rotate Unit.
 * 
 *  Component registers are Shift/Rotate Buffer, Shift/Rotate Direction Register
 *  Shift/Rotate Type Register, Shift/Rotate Count Register and the Shift/Rotate
 *  Carry Buffer.
 *  
 * Note that condition codes are cleared upon invocation of an SRU operation and
 * the current condition state remains valid for several operations following an 
 * SRU instruction as long as no other instruction is called that may also result 
 * in a condition code being set such as ALU operations.
 * 
 * Shift and Rotate operations are zero based meaning that even with a value of
 * zero supplied to the count register, a shift or rotate will be carried out.  If
 * a full shift or rotate of a 16-bit word is required, the count should be set to
 * fifteen.  This convention is observed because the count register is 4 bits.
 * 
 * The shift/rotate buffer contains the word to be shifted/rotated.  The shift/rotate 
 * buffer acts both as the input buffer and the result buffer.
 * 
 * The direction register is a single bit.  If the direction is zero, the shift/rotate
 * will be to the right.  If the direction is one, the shift/rotate will be to the
 * left.
 * 
 * The type register is a single bit.  If the type is zero, the shift/rotate will be
 * arithmetic and will therefore preserve the zero bit of the shift/rotate buffer.  If
 * the type is one, the shift/rotate will be logical and will operate on all bits of
 * the shift/rotate buffer.
 * 
 * The carry buffer will be filled by the last value shifted or rotated out of the 
 * shift/rotate buffer due to an operation. 
 * */


package cpu.components;

import cpu.datastores.*;
import cpu.interfaces.EventListener;

public class SRU {
	
	public static final boolean ARITHMETIC = true;
	public static final boolean LOGICAL = false;
	public static final boolean RIGHT = false;
	public static final boolean LEFT = true;
	
	// Shift\Rotate Buffer Register
	public Register16 SRB;
	
	// Shift\Rotate Direction Register
	// 0 -> right; 1 -> left;  
	public Register1 SRD;
	
	// Shift\Rotate Type Register
	// 0 -> arithmetic; 1 -> logical;
	public Register1 SRT;
	
	// Shift\Rotate Count Register
	// Represents the number of additional shift or rotates
	// zero assumes that one shift or rotate is required.
	public Register4 SRCT;
	
	// Shift\Rotate Carry Buffer Register
	public Register1 SRCB;
	
	private cpu.components.CPU cpu;
	
	public SRU( cpu.components.CPU cpu ) {
		this.cpu = cpu;
		
		SRB = new Register16( );
		SRD = new Register1( );
		SRT = new Register1( );
		SRCT = new Register4( );
		SRCB = new Register1( );
	}
	// shift operation
	public void shift( ) {
		cpu.controlunit.cc( ControlUnit.UNDERFLOW, false);
		cpu.controlunit.cc( ControlUnit.OVERFLOW, false);
		cpu.controlunit.cc( ControlUnit.DIVBYZERO, false);
		cpu.controlunit.cc( ControlUnit.EQUALORNOT, false);

		int count = SRCT.toJavaInt( );
		
		do {
			if( SRT.bit( 0 ).value == ARITHMETIC ) { 
				//arithmetic shift
				if( SRD.bit( 0 ).value == LEFT ) {
					// left shift
					if( SRB.bit( 15 ).value == true ) {
						cpu.controlunit.cc( ControlUnit.OVERFLOW ).value = true;
					}
					SRCB.bit( 0 ).value = SRB.bit( 15 ).value;
					for( int i = 15; i > 1; i-- )
						SRB.bit( i ).value = SRB.bit( i - 1 ).value; 
					SRB.bit( 1 ).value = false;
				} else {
					// right shift
					if( SRB.bit( 1 ).value == true ) {
						cpu.controlunit.cc( ControlUnit.UNDERFLOW ).value = true;
					}
					SRCB.bit( 0 ).value = SRB.bit( 1 ).value;
					for( int i = 1; i < 15; i++ )
						SRB.bit( i ).value = SRB.bit( i + 1 ).value; 
					SRB.bit( 15 ).value = false;
				}
			} else {
				// logical shift
				if( SRD.bit( 0 ).value == LEFT ) {
					// left shift
					if( SRB.bit( 15 ).value == true ) {
						cpu.controlunit.cc( ControlUnit.OVERFLOW ).value = true;
					}
					SRCB.bit( 0 ).value = SRB.bit( 15 ).value;
					for( int i = 15; i > 0; i-- )
						SRB.bit( i ).value = SRB.bit( i - 1 ).value; 
					SRB.bit( 0 ).value = false;
				} else {
					// right shift
					if( SRB.bit( 0 ).value == true ) {
						cpu.controlunit.cc( ControlUnit.UNDERFLOW ).value = true;
					}
					SRCB.bit( 0 ).value = SRB.bit( 0 ).value;
					for( int i = 0; i < 15; i++ )
						SRB.bit( i ).value = SRB.bit( i + 1 ).value; 
					SRB.bit( 15 ).value = false;
				}
			}
			if( count > 0 )
				count--;
		} while( count > 0 );
	}
	// rotate operation
	public void rotate( ) {
		cpu.controlunit.cc( ControlUnit.UNDERFLOW, false);
		cpu.controlunit.cc( ControlUnit.OVERFLOW, false);
		cpu.controlunit.cc( ControlUnit.DIVBYZERO, false);
		cpu.controlunit.cc( ControlUnit.EQUALORNOT, false);

		int count = SRCT.toJavaInt( );
		
		do {
			if( SRT.bit( 0 ).value == ARITHMETIC ) { 
				//arithmetic rotate
				if( SRD.bit( 0 ).value == LEFT ) {
					// left rotate
					SRCB.bit( 0 ).value = SRB.bit( 15 ).value;
					for( int i = 15; i > 1; i-- )
						SRB.bit( i ).value = SRB.bit( i - 1 ).value; 
					SRB.bit( 1 ).value = SRCB.bit( 0 ).value;
				} else {
					// right rotate
					SRCB.bit( 0 ).value = SRB.bit( 1 ).value;
					for( int i = 1; i < 15; i++ )
						SRB.bit( i ).value = SRB.bit( i + 1 ).value; 
					SRB.bit( 15 ).value = SRCB.bit( 0 ).value;
				}
			} else {
				// logical rotate
				if( SRD.bit( 0 ).value == LEFT ) {
					// left rotate
					SRCB.bit( 0 ).value = SRB.bit( 15 ).value;
					for( int i = 15; i > 0; i-- )
						SRB.bit( i ).value = SRB.bit( i - 1 ).value; 
					SRB.bit( 0 ).value = SRCB.bit( 0 ).value;
				} else {
					// right rotate
					SRCB.bit( 0 ).value = SRB.bit( 0 ).value;
					for( int i = 0; i < 15; i++ )
						SRB.bit( i ).value = SRB.bit( i + 1 ).value; 
					SRB.bit( 15 ).value = SRCB.bit( 0 ).value;
				}
			}
			if( count > 0 )
				count--;
		} while( count > 0 );
	}
}
